package org.example.facade.component;

import javafx.scene.Cursor;
import javafx.scene.layout.VBox;
import org.example.business_logic.component.*;
import org.example.physics_engine.body.Mass;
import org.example.physics_engine.geometry.Vector2d;
import org.example.facade.panel.GizmoPhysicsBody;

import java.util.function.Function;

import static org.example.business_logic.Settings.HOLE_BIAS;

public class Component_Draggable extends ImgLabel{
    protected static final Function<Vector2d, GizmoPhysicsBody> ballBodyCreator = (preferredSize) -> {
        Ball ball = new Ball(preferredSize.x / 2.0);
        GizmoPhysicsBody gizmoPhysicsBody = new GizmoPhysicsBody(ball);
        gizmoPhysicsBody.setMass(gizmoPhysicsBody.getShape().createMass(1));
        gizmoPhysicsBody.setRestitution(0.95);
        gizmoPhysicsBody.setFriction(0.4);
        gizmoPhysicsBody.setRestitutionVelocity(10);
        return gizmoPhysicsBody;
    };


    protected static final Function<Vector2d, GizmoPhysicsBody> circleBodyCreator = (preferredSize) -> {
        CircleBarrier circle = new CircleBarrier(preferredSize.x / 2.0);
        GizmoPhysicsBody gizmoPhysicsBody = new GizmoPhysicsBody(circle);
        gizmoPhysicsBody.setMass(new Mass(new Vector2d(), 0.0, 0.0));
        gizmoPhysicsBody.setRestitution(0.95);
        gizmoPhysicsBody.setFriction(0.5);
        gizmoPhysicsBody.setRestitutionVelocity(10);
        return gizmoPhysicsBody;
    };

    protected static final Function<Vector2d, GizmoPhysicsBody> blackHoleBodyCreator = (preferredSize) -> {
        Hole blackhole = new Hole(preferredSize.x / 2.0 - HOLE_BIAS);
        GizmoPhysicsBody gizmoPhysicsBody = new GizmoPhysicsBody(blackhole);
        gizmoPhysicsBody.setMass(new Mass(new Vector2d(), 0.0, 0.0));
        return gizmoPhysicsBody;
    };

    protected static final Function<Vector2d, GizmoPhysicsBody> rectangleBodyCreator = (preferredSize) -> {
        RectangleBarrier rectangle = new RectangleBarrier(preferredSize.x / 2.0, preferredSize.y / 2.0);
        GizmoPhysicsBody gizmoPhysicsBody = new GizmoPhysicsBody(rectangle);
        gizmoPhysicsBody.setMass(new Mass(new Vector2d(), 0.0, 0.0));
        gizmoPhysicsBody.setRestitution(0.95);
        gizmoPhysicsBody.setFriction(0.5);
        gizmoPhysicsBody.setRestitutionVelocity(10);
        return gizmoPhysicsBody;
    };

    protected static final Function<Vector2d, GizmoPhysicsBody> pipeBodyCreator = (preferredSize) -> {
        StraightOrbit pipe = new StraightOrbit(preferredSize.x / 2.0, preferredSize.y / 2.0);
        GizmoPhysicsBody gizmoPhysicsBody = new GizmoPhysicsBody(pipe);
        gizmoPhysicsBody.setMass(new Mass(new Vector2d(), 0.0, 0.0));
        gizmoPhysicsBody.setRestitution(0.95);
        gizmoPhysicsBody.setFriction(0.0);
        gizmoPhysicsBody.setRestitutionVelocity(10);
        return gizmoPhysicsBody;
    };

    protected static final Function<Vector2d, GizmoPhysicsBody> curvedPipeBodyCreator = (preferredSize) -> {
        CurvedOrbit curvedPipe = new CurvedOrbit(preferredSize.x);
        GizmoPhysicsBody gizmoPhysicsBody = new GizmoPhysicsBody(curvedPipe);
        gizmoPhysicsBody.setMass(new Mass(new Vector2d(), 0.0, 0.0));
        gizmoPhysicsBody.setRestitution(0.95);
        gizmoPhysicsBody.setFriction(0.0);
        return gizmoPhysicsBody;
    };
    protected static final Function<Vector2d, GizmoPhysicsBody> triangleBodyCreator = (preferredSize) -> {
        Vector2d[] vertices = new Vector2d[]{
                new Vector2d(-preferredSize.x / 2.0, -preferredSize.y / 2.0),
                new Vector2d(preferredSize.x / 2.0, -preferredSize.y / 2.0),
                new Vector2d(-preferredSize.x / 2.0, preferredSize.y / 2.0)
        };
        TriangleBarrier triangle = new TriangleBarrier(vertices);
        GizmoPhysicsBody gizmoPhysicsBody = new GizmoPhysicsBody(triangle);
        gizmoPhysicsBody.setMass(new Mass(new Vector2d(), 0.0, 0.0));
        gizmoPhysicsBody.setRestitution(0.95);
        gizmoPhysicsBody.setFriction(0.5);
        gizmoPhysicsBody.setRestitutionVelocity(10);
        return gizmoPhysicsBody;
    };

    protected static final Function<Vector2d, GizmoPhysicsBody> leftFlipperBodyCreator = (preferredSize) -> {
        Vector2d[] vertices = new Vector2d[]{
                new Vector2d(-preferredSize.x / 2.0, -preferredSize.y / 4.0 / 2.0),
                new Vector2d(preferredSize.x / 2.0, -preferredSize.y / 4.0 / 2.0),
                new Vector2d(-preferredSize.x / 2.0, preferredSize.y / 4.0 / 2.0)
        };
        Baffle baffle = new Baffle(vertices, Baffle.Direction.LEFT);
        GizmoPhysicsBody gizmoPhysicsBody = new GizmoPhysicsBody(baffle);
        gizmoPhysicsBody.setMass(new Mass(new Vector2d(), 0.0, 0.0));
        gizmoPhysicsBody.setRestitution(0.95);
        gizmoPhysicsBody.setFriction(0.5);
        gizmoPhysicsBody.setRestitutionVelocity(10);
        return gizmoPhysicsBody;
    };

    protected static final Function<Vector2d, GizmoPhysicsBody> rightFlipperBodyCreator = (preferredSize) -> {
        Vector2d[] vertices = new Vector2d[]{
                new Vector2d(-preferredSize.y / 2.0, -preferredSize.y / 4.0 / 2.0),
                new Vector2d(preferredSize.x / 2.0, -preferredSize.y / 4.0 / 2.0),
                new Vector2d(preferredSize.y / 2.0, preferredSize.y / 4.0 / 2.0)
        };
        Baffle baffle = new Baffle(vertices, Baffle.Direction.RIGHT);
        GizmoPhysicsBody gizmoPhysicsBody = new GizmoPhysicsBody(baffle);
        gizmoPhysicsBody.setMass(new Mass(new Vector2d(), 0.0, 0.0));
        gizmoPhysicsBody.setRestitution(0.95);
        gizmoPhysicsBody.setFriction(0.5);
        gizmoPhysicsBody.setRestitutionVelocity(10);
        return gizmoPhysicsBody;
    };


    private Component_Type componentType;

    public Component_Draggable(String resource, String labelText, Component_Type componentType) {
        super(resource, labelText);
        this.componentType = componentType;
    }


    @Override
    public VBox createVBox() {
        VBox vBox = super.createVBox();
        this.getImageView().setCursor(Cursor.HAND);
        return vBox;
    }

    /**
     * Create a physics body for this gizmo.
     *
     * @param preferredSize the preferred size of the gizmo.
     * @param center        the center of the gizmo.
     * @return the physics body.
     */
    public GizmoPhysicsBody createPhysicsBody(Vector2d preferredSize, Vector2d center) {
        GizmoPhysicsBody physicsBody = (GizmoPhysicsBody) componentType.getPhysicsBodySupplier().apply(preferredSize);
        physicsBody.getShape().translate(center);
        physicsBody.setComponentType(componentType);
        return physicsBody;
    }
}
